package com.xinyi.share.weixin;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import net.sf.ezmorph.bean.MorphDynaBean;
import net.sf.json.JSONObject;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.xinyi.share.utils.RequestUtils;
import com.xinyi.share.utils.SecurityKeys;
import com.xinyi.share.weixin.entity.MenuButton;
import com.xinyi.share.weixin.message.Message;
import com.xinyi.share.weixin.utils.MessageUtils;
import com.xinyi.share.weixin.vo.Group;
import com.xinyi.share.weixin.vo.ListUserVo;
import com.xinyi.share.weixin.vo.Media;
import com.xinyi.share.weixin.vo.UserVo;

/**
 * 微信核心类
 * 
 * @author wangchuan
 *
 */
@SuppressWarnings("unchecked")
public final class WeixinCore {
	private final static Logger logger = Logger.getLogger(WeixinCore.class);

	private final static String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token";
	private final static String menuCreateUrl = "https://api.weixin.qq.com/cgi-bin/menu/create";
	private final static String menuListUrl = "https://api.weixin.qq.com/cgi-bin/menu/get";
	private final static String menuDeleteUrl = "https://api.weixin.qq.com/cgi-bin/menu/delete";
	private final static String groupCreateUrl = "https://api.weixin.qq.com/cgi-bin/groups/create";
	private final static String groupUpdateUrl = "https://api.weixin.qq.com/cgi-bin/groups/update";
	private final static String groupListUrl = "https://api.weixin.qq.com/cgi-bin/groups/get";
	private final static String userListUrl = "https://api.weixin.qq.com/cgi-bin/user/get";
	private final static String userInfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info";
	// private final static String uploadMediaUrl =
	// "http://file.api.weixin.qq.com/cgi-bin/media/upload";
	private final static String downloadMediaUrl = "http://file.api.weixin.qq.com/cgi-bin/media/get";
	private static AccessTokenEntity accessTokenEntity = null;

	/**
	 * 验证请求合法性
	 * 
	 * @param signatrue
	 * @param timestamp
	 * @param nonce
	 * @return
	 */
	public static boolean checkSignature(String signature, String timestamp, String nonce) {
		if (StringUtils.isEmpty(signature) || StringUtils.isEmpty(timestamp) || StringUtils.isEmpty(nonce))
			return false;
		List<String> list = new LinkedList<>();
		list.add(SecurityKeys.getInstance().getWeixinConfig().getToken());
		list.add(timestamp);
		list.add(nonce);
		Collections.sort(list);
		StringBuilder builder = new StringBuilder();
		Iterator<String> it = list.iterator();
		while (it.hasNext()) {
			builder.append(it.next());
		}
		String codecStr = DigestUtils.sha1Hex(builder.toString());
		return StringUtils.equals(codecStr, signature);
	}

	/**
	 * 
	 * @Title: messageFormat
	 * @Description: 微信消息格式化
	 * @param message
	 * @return
	 * @return Message
	 * @throws
	 */
	public static Message messageFormat(String message) {
		return MessageUtils.formatXml(message);
	}

	/**
	 * 创建菜单
	 * 
	 * @return
	 */
	public static String createSelfMenu(List<MenuButton> menuButtons) {
		Map<String, List<MenuButton>> menusMap = new HashMap<String, List<MenuButton>>();
		menusMap.put("button", menuButtons);
		StringBuilder urlBuilder = new StringBuilder(menuCreateUrl);
		String accesstoken = getAccessToken();
		urlBuilder.append("?").append("access_token").append("=").append(accesstoken);
		JSONObject object = JSONObject.fromObject(menusMap);
		String resstr = RequestUtils.post(urlBuilder.toString(), object.toString());
		Map<String, Object> map = jsonToMap(resstr);
		if (map.containsKey("errcode") && null != map.get("errcode") && StringUtils.equals("0", map.get("errcode").toString())) {
			return null;
		}
		logger.error("创建菜单失败!返回信息为:" + (map.containsKey("errcode") ? map.get("errcode") : ""));
		if (object.containsKey("errmsg"))
			return object.getString("errmsg");
		return "创建菜单失败";
	}

	/**
	 * 
	 * @description 查询菜单
	 * @return String
	 * @author wangchuan
	 * @throws
	 */
	public static String listSelfMenu() {
		return RequestUtils.get(menuListUrl, getAccessParamsMap());
	}

	/**
	 * 
	 * @description 删除自定义菜单
	 * @return 空表示成功
	 * @author wangchuan
	 * @throws
	 */
	public static String deleteSelfMenu() {
		String result = RequestUtils.get(menuDeleteUrl, getAccessParamsMap());
		JSONObject object = JSONObject.fromObject(result);
		if (object.containsKey("errcode")) {
			String errcode = object.getString("errcode");
			if (StringUtils.equals(errcode, "0"))
				return null;
		}
		logger.error("删除菜单失败!返回信息为:" + (object.containsKey("errcode") ? object.get("errcode") : ""));
		if (object.containsKey("errmsg"))
			return object.getString("errmsg");
		return "操作失败";
	}

	/**
	 * 
	 * @description 上传素材
	 * @return void
	 * @author wangchuan
	 * @throws
	 */
	public static void uploadMedia(Media media, File file) {
		StringBuilder urlBuilder = new StringBuilder(menuCreateUrl);
		String accesstoken = getAccessToken();
		urlBuilder.append("?").append("access_token").append("=").append(accesstoken);
		urlBuilder.append("&").append("type").append("=").append(media.toString());

	}

	/**
	 * 
	 * @Title: downloadMedia
	 * @Description: 下载素材
	 * @param mediaid
	 * @return void
	 * @throws
	 */
	public static InputStream downloadMedia(String mediaid) {
		Map<String, String> params = getAccessParamsMap();
		params.put("media_id", mediaid);
		return RequestUtils.getStream(downloadMediaUrl, params);
	}

	/**
	 * 
	 * @Title: createGroup
	 * @Description: 创建分组
	 * @param name
	 * @return
	 * @return boolean
	 * @throws
	 */
	public static String createGroup(String name) {
		Map<String, String> params = getAccessParamsMap();
		String result = RequestUtils.post(groupCreateUrl, params, MessageUtils.groupPostString(null, name));
		Map<String, Object> map = jsonToMap(result);
		if (map.containsKey("errcode")) {
			logger.error("创建分组失败，失败状态码为:" + map.get("errcode") + "\t消息为:" + map.get("errmsg"));
			return null;
		}
		Object obj = map.get("group");
		if (obj instanceof JSONObject) {
			JSONObject object = (JSONObject) obj;
			return object.getString("id");
		}
		return null;
	}

	/**
	 * 
	 * @Title: updateGroup
	 * @Description: 更新分组
	 * @param id
	 * @param name
	 * @return
	 * @return boolean
	 * @throws
	 */
	public static boolean updateGroup(String id, String name) {
		Map<String, String> params = getAccessParamsMap();
		String result = RequestUtils.post(groupUpdateUrl, params, MessageUtils.groupPostString(id, name));
		Map<String, Object> map = jsonToMap(result);
		if (map.containsKey("errcode")) {
			String errcode = (String) map.get("errcode");
			if (StringUtils.equals(errcode, "0"))
				return true;
			logger.error("更新分组失败，失败状态码为:" + map.get("errcode") + "\t消息为:" + map.get("errmsg"));
		}
		return false;
	}

	/**
	 * 
	 * @Title: listGroup
	 * @Description: 用户分组获取
	 * @return
	 * @return List<Group>
	 * @throws
	 */
	public static List<Group> listGroup() {
		String result = RequestUtils.get(groupListUrl, getAccessParamsMap());
		if (StringUtils.isNotEmpty(result)) {
			Map<String, Object> map = jsonToMap(result);
			if (map.containsKey("errcode")) {
				logger.error("获取用户分组失败，失败状态码为:" + map.get("errcode") + "\t消息为:" + map.get("errmsg"));
				return null;
			}
			List<MorphDynaBean> list = (List<MorphDynaBean>) map.get("groups");
			List<Group> groups = new ArrayList<Group>();
			for (MorphDynaBean morphDynaBean : list) {
				Group group = new Group();
				group.setId((int) morphDynaBean.get("id"));
				group.setName((String) morphDynaBean.get("name"));
				group.setCount((int) morphDynaBean.get("count"));
				groups.add(group);
			}
			return groups;
		}
		return null;
	}

	/**
	 *
	 * @Title: listUserId
	 * @Description: 获取关注用户
	 * @return
	 * @return ListUserVo
	 * @throws
	 */
	public static ListUserVo listUserId() {
		ListUserVo vo = new ListUserVo();
		fromatListUserRes(vo, null);
		return vo;
	}

	/**
	 * 
	 * @Title: listUserInfo
	 * @Description: 获取用户详情
	 * @param openid
	 * @return
	 * @return UserVo
	 * @throws
	 */
	public static UserVo listUserInfo(String openid) {
		Map<String, String> params = getAccessParamsMap();
		params.put("openid", openid);
		params.put("lang", "zh_CN");
		String result = RequestUtils.get(userInfoUrl, params);
		if (StringUtils.isNotEmpty(result)) {
			UserVo userVo = new UserVo();
			Map<String, Object> map = jsonToMap(result);
			userVo.setSubscribe((int) map.get("subscribe"));
			userVo.setOpenid((String) map.get("openid"));
			userVo.setNickname((String) map.get("nickname"));
			userVo.setSex((int) map.get("sex"));
			userVo.setCity((String) map.get("city"));
			userVo.setCountry((String) map.get("country"));
			userVo.setProvince((String) map.get("province"));
			userVo.setLanguage((String) map.get("language"));
			userVo.setHeadimgurl((String) map.get("headimgurl"));
			userVo.setSubscribetime((int) map.get("subscribe_time"));
			userVo.setUnionid((String) map.get("unionid"));
			return userVo;
		}
		return null;
	}

	/**
	 * 
	 * @Title: fromatListUserRes
	 * @Description: 格式化获取用户返回的JSON
	 * @param vo
	 * @param nextid
	 * @return void
	 * @throws
	 */
	private static void fromatListUserRes(ListUserVo vo, String nextid) {
		String result = listUsers(nextid);
		if (StringUtils.isNotEmpty(result)) {
			Map<String, Object> map = jsonToMap(result);
			if (map.containsKey("errcode")) {
				logger.error("获取用户ID，失败状态码为:" + map.get("errcode") + "\t消息为:" + map.get("errmsg"));
			}
			int total = (int) map.get("total");
			vo.setTotal(total);
			int count = (int) map.get("count");
			nextid = (String) map.get("next_openid");
			MorphDynaBean morphDynaBean = (MorphDynaBean) map.get("data");
			List<String> list = (List<String>) morphDynaBean.get("openid");
			Iterator<String> it = list.iterator();
			if (it.hasNext()) {
				String userid = it.next();
				vo.addUserOpenId(userid);
			}
			if (total > count)
				fromatListUserRes(vo, nextid);
		}
	}

	/**
	 * 
	 * @Title: listUsers
	 * @Description: 获取用户列表string
	 * @param nextid
	 * @return
	 * @return String
	 * @throws
	 */
	private static String listUsers(String nextid) {
		Map<String, String> params = getAccessParamsMap();
		if (StringUtils.isNotEmpty(nextid))
			params.put("next_openid", nextid);
		return RequestUtils.get(userListUrl, params);
	}

	/**
	 * 将JSON转换为map
	 * 
	 * @param json
	 * @return
	 */
	private static Map<String, Object> jsonToMap(String json) {
		JSONObject jsonObject = JSONObject.fromObject(json);
		Map<String, Object> map = (Map<String, Object>) JSONObject.toBean(jsonObject, Map.class);
		return map;
	}

	/**
	 * 获取access_token
	 * 
	 * @return
	 */
	private static String getAccessToken() {
		if (null == accessTokenEntity || !accessTokenEntity.isEffective(System.currentTimeMillis())) {
			Map<String, String> params = new HashMap<>();
			params.put("grant_type", "client_credential");
			params.put("appid", SecurityKeys.getInstance().getWeixinConfig().getAppid());
			params.put("secret", SecurityKeys.getInstance().getWeixinConfig().getAppsecret());
			String resstr = RequestUtils.get(accessTokenUrl, params);
			if (StringUtils.isNotEmpty(resstr)) {
				Map<String, Object> map = jsonToMap(resstr);
				String access_token = (String) map.get("access_token");
				long expires_in = (long) (Integer) map.get("expires_in");
				long currentTime = System.currentTimeMillis();
				accessTokenEntity = new AccessTokenEntity();
				accessTokenEntity.setAccesstoken(access_token);
				accessTokenEntity.setCurrenttimes(currentTime);
				accessTokenEntity.setExpiresin(expires_in);
				return access_token;
			}
		} else {
			return accessTokenEntity.getAccesstoken();
		}
		return null;
	}

	/**
	 * 
	 * @Title: getAccessParamsMap
	 * @Description: 获取access并返回map
	 * @return
	 * @return Map<String,String>
	 * @throws
	 */
	private static Map<String, String> getAccessParamsMap() {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", getAccessToken());
		return params;
	}

	public static void main(String[] args) {
		List<Group> groups = listGroup();
		System.out.println(groups);
		// ListUserVo vo = listUserId();
		// for(String openid:vo.getData()){
		// System.out.println(listUserInfo(openid));
		// }
	}
}
